package com.ling.feign.plus.advice;

import com.google.gson.Gson;
import com.ling.common.Result;
import com.ling.feign.plus.FeignExceptionConstant;
import com.ling.feign.plus.annotation.AutoPackaging;
import org.springframework.core.MethodParameter;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;

import java.util.Objects;

@RestControllerAdvice
public class AutoPackagingResponseBodyAdvice implements ResponseBodyAdvice {
    @Override
    public boolean supports(MethodParameter methodParameter, Class aClass) {
        return true;
    }

    @Override
    public Object beforeBodyWrite(Object returnValue,
                                  MethodParameter returnType,
                                  MediaType selectedContentType,
                                  Class selectedConverterType,
                                  ServerHttpRequest request,
                                  ServerHttpResponse response) {

        AutoPackaging autoPackaging = returnType.getAnnotatedElement().getAnnotation(AutoPackaging.class);
        if (Objects.nonNull(autoPackaging) && !autoPackaging.value()) {
            return returnValue;
        }
        //应用间调用不处理
        HttpHeaders httpHeaders = request.getHeaders();
        if (httpHeaders.containsKey(FeignExceptionConstant.FEIGN_CALLER_HEADER)) {
            return returnValue;
        }

        //swagger相关接口不处理
        if (request.getURI().getPath().contains("swagger-resources") ||
                request.getURI().getPath().contains("v2/api-docs")) {
            return returnValue;
        }


        response.getHeaders().set(HttpHeaders.CONTENT_TYPE, "application/json;charset=UTF-8");

        Result<?> result;
        //获取返回值类型
        String returnClassType = returnType.getParameterType().getName();

        //如果返回值类型为void，则默认返回成功
        if (Void.TYPE.getName().equals(returnClassType)) {
            result = Result.success();
        } else if (Result.class.getName().equals(returnClassType) ||
                Result.class.getName().equals(returnType.getParameterType().getSuperclass().getName())) {
            result = (Result<?>) returnValue;
        } else if (String.class.getName().equals(returnClassType)) {
            //返回类型为String封装后必须再次转为json格式的String
            //不转的话StringHttpMessageConverter出抛出ClassCastException异常
            //异常原因:
            //      步骤1: Spring加载所有可用的HttpMessageConverter
            //            此时StringHttpMessageConverter已被加载并且标记supports==true可用状态
            //      步骤2: 调用beforeBodyWrite进行统一的返回封装，此时返回的String类型被改为Result类
            //      步骤3: 调用StringHttpMessageConverter中的getContentLength()方法,
            //             此时返回类型已更改，类转换异常并抛出ClassCastException
            //解决原理:
            //      当返回类型为String时，将步骤2中得到的Result做toJSONString处理,
            //      使返回类型重新更改为String
            result = Result.success(returnValue);

            return new Gson().toJson(result);
        } else {
            if (Objects.isNull(returnValue)) {
                result = Result.success();
            } else {
                result = Result.success(returnValue);
            }
        }
        return result;
    }
}